home *** CD-ROM | disk | FTP | other *** search
/ Aminet 52 / Aminet 52 (2002)(GTI - Schatztruhe)[!][Dec 2002].iso / Aminet / dev / gg / bing-1.1.3.lha / bing-1.1.3 / src / bing.c next >
C/C++ Source or Header  |  1997-06-06  |  42KB  |  1,675 lines

  1. /*
  2.  *          Unofficial release 1.1.3
  3.  *            B I N G
  4.  *
  5.  * Using the InterNet Control Message Protocol (ICMP) "ECHO" facility,
  6.  * measure point-to-point bandwidth.
  7.  *
  8.  * Hack by Pierre Beyssac (pb@fasterix.freenix.fr), based on FreeBSD ping.
  9.  * Comments and bug reports welcome !
  10.  *
  11.  * Original ping author -
  12.  *    Mike Muuss
  13.  *    U. S. Army Ballistic Research Laboratory
  14.  *    December, 1983
  15.  *
  16.  *
  17.  * Copyright (c) 1995,1997 Pierre Beyssac.
  18.  * All rights reserved.
  19.  *
  20.  * Redistribution and use in source and binary forms, with or without
  21.  * modification, are permitted provided that the following conditions
  22.  * are met:
  23.  * 1. Redistributions of source code must retain the above copyright
  24.  *    notice, this list of conditions and the following disclaimer.
  25.  * 2. Redistributions in binary form must reproduce the above copyright
  26.  *    notice, this list of conditions and the following disclaimer in the
  27.  *    documentation and/or other materials provided with the distribution.
  28.  * 3. All advertising materials mentioning features or use of this software
  29.  *    must display the following acknowledgement:
  30.  *    This product includes software developed by Pierre Beyssac,
  31.  *    Mike Muss, the University of California, Berkeley and its contributors.
  32.  * 4. Neither the name of the author nor the names of any co-contributors
  33.  *    may be used to endorse or promote products derived from this software
  34.  *    without specific prior written permission.
  35.  *
  36.  * THIS SOFTWARE IS PROVIDED BY PIERRE BEYSSAC AND CONTRIBUTORS ``AS IS'' AND
  37.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  38.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  39.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  40.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  41.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  42.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  43.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  44.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  45.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  46.  * SUCH DAMAGE.
  47.  *
  48.  */
  49.  
  50. /* The original UCB copyright notice follows */
  51.  
  52. /*
  53.  * Copyright (c) 1989 The Regents of the University of California.
  54.  * All rights reserved.
  55.  *
  56.  * This code is derived from software contributed to Berkeley by
  57.  * Mike Muuss.
  58.  *
  59.  * Redistribution and use in source and binary forms, with or without
  60.  * modification, are permitted provided that the following conditions
  61.  * are met:
  62.  * 1. Redistributions of source code must retain the above copyright
  63.  *    notice, this list of conditions and the following disclaimer.
  64.  * 2. Redistributions in binary form must reproduce the above copyright
  65.  *    notice, this list of conditions and the following disclaimer in the
  66.  *    documentation and/or other materials provided with the distribution.
  67.  * 3. All advertising materials mentioning features or use of this software
  68.  *    must display the following acknowledgement:
  69.  *    This product includes software developed by the University of
  70.  *    California, Berkeley and its contributors.
  71.  * 4. Neither the name of the University nor the names of its contributors
  72.  *    may be used to endorse or promote products derived from this software
  73.  *    without specific prior written permission.
  74.  *
  75.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  76.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  77.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  78.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  79.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  80.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  81.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  82.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  83.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  84.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  85.  * SUCH DAMAGE.
  86.  *
  87.  */
  88.  
  89. #ifndef lint
  90. char copyright[] =
  91. "@(#) Copyright (c) 1989 The Regents of the University of California.\n\
  92.  All rights reserved.\n";
  93. #endif /* not lint */
  94.  
  95. #ifndef lint
  96. static char rcsid[] = "$Id: bing.c,v 1.17 1997/01/23 21:00:03 pb Exp $";
  97. #endif /* not lint */
  98.  
  99. /* Usual includes/declarations */
  100. #include <stdio.h>
  101. #include <stdlib.h>
  102. #include <sys/types.h>
  103. #include <errno.h>
  104. #include <math.h>
  105.  
  106. /* More specific includes/declarations */
  107. #include <limits.h>
  108. #include <ctype.h>
  109. #include <string.h>
  110. #include <memory.h>
  111.  
  112. #ifdef WIN32
  113.  
  114. /* This variable is expected by getopt.c */
  115. char* __progname;
  116.  
  117. #else
  118.  
  119. /* #include <unistd.h> */
  120. #include <time.h>
  121.  
  122. #include <sys/param.h>
  123. /* #include <sys/file.h> */
  124. #include <sys/time.h>
  125. #include <signal.h>
  126. #include <math.h>
  127.  
  128. #endif /* WIN32 */
  129.  
  130. /* Network includes/definitions */
  131.  
  132. #ifdef WIN32
  133.  
  134. #define MAXHOSTNAMELEN    64
  135.  
  136. #include "win32/win32.h"
  137. #include <winsock.h>
  138. #include "win32/types.h"
  139.  
  140. #else
  141.  
  142. #include <netinet/in_systm.h>
  143. #include <netinet/in.h>
  144.  
  145. #include <netdb.h>
  146. #include <sys/socket.h>
  147. #include <arpa/inet.h>
  148.  
  149. #endif /* WIN32 */
  150.  
  151. /* These come either from the compatibility library or from the
  152.  * standard libraries.
  153.  */
  154. #include <netinet/ip.h>
  155. #include <netinet/ip_var.h>
  156. #include <netinet/ip_icmp.h>
  157.  
  158. #include "mod_icmp.h"
  159.  
  160. /* System dependent apsects */
  161. #ifdef NO_RANDOM
  162. #define random        rand
  163. #define srandom        srand
  164. #endif
  165.  
  166. #ifdef NO_STRERROR
  167. int sys_nerr;
  168. char *sys_errlist[];
  169. char *sys_unk = "Unknown error";
  170. #define strerror(e)    (((e)>=sys_nerr||(e)<0)?sys_unk:sys_errlist[(e)])
  171. #endif
  172.  
  173. #ifdef NO_SNPRINTF
  174. #define snprintf sprintf
  175. #define snfargs(str,size,format) str,format
  176. #else
  177. #ifdef WIN32
  178. #define snprintf _snprintf
  179. #endif
  180. #define snfargs(str,size,format) str,size,format
  181. #endif
  182.  
  183.  
  184.  
  185. #define    ICMP_TO_DATA(icp)    ((u_char *)((icp)->icmp_data))
  186.  
  187. /*
  188.  * The default small packet size should be big enough that no padding
  189.  * needs to be done at the physical level (ethernet typically requires this).
  190.  *
  191.  * The initial value was chosen to be 8 bytes, just enough to
  192.  * contain a struct timeval, but it proved too small. The current value is
  193.  * chosen to be around 40 bytes. If you add the IP and ICMP headers, that
  194.  * should be more than the minimal ethernet packet size.
  195.  *
  196.  * 44 is nice because that's 64 bytes less than the other value, which
  197.  * has not been changed.
  198.  *
  199.  * The default big packet size is not too big so as not to waste resources
  200.  * unless the user explicitly chooses to.
  201.  */
  202.  
  203. #define    DEFDATALEN_SMALL    44    /* default small data len */
  204. #define    DEFDATALEN_BIG        108    /* default big data len */
  205.  
  206. #define    MAXIPLEN    60
  207. #define    MAXICMPLEN    76
  208. #define    MAXPACKET    (65536 - 60 - 8)/* max packet size */
  209. #define    MAXWAIT        10        /* max seconds to wait for response */
  210. #define    NROUTES        9        /* number of record route slots */
  211.  
  212. #define    A(bit,tbl)    (tbl)[(unsigned)(bit)>>3] /* identify byte in array */
  213. #define    B(bit)        (1 << ((bit) & 0x07))    /* identify bit in byte */
  214. #define    SET(bit,tbl)    (A(bit,(tbl)) |= B(bit))
  215. #define    CLR(bit,tbl)    (A(bit,(tbl)) &= (~B(bit)))
  216. #define    TST(bit,tbl)    (A(bit,(tbl)) & B(bit))
  217.  
  218. /* various options */
  219. int options;
  220. #define    F_NODELTA    0x001
  221. #define    F_INTERVAL    0x002
  222. #define    F_NUMERIC    0x004
  223. #define    F_PINGFILLED    0x008
  224. #define    F_VVERBOSE    0x010
  225. #define    F_RROUTE    0x020
  226. #define    F_SO_DEBUG    0x040
  227. #define    F_SO_DONTROUTE    0x080
  228. #define    F_VERBOSE    0x100
  229. #define    F_RANDOMFILL    0x200
  230. #define    F_PEDANTIC    0x400
  231. #define    F_WARN        0x800
  232.  
  233. /* multicast options */
  234. int moptions;
  235. #define MULTICAST_NOLOOP    0x001
  236. #define MULTICAST_TTL        0x002
  237. #define MULTICAST_IF        0x004
  238.  
  239. /*
  240.  * MAX_DUP_CHK is the number of bits in received table, i.e. the maximum
  241.  * number of received sequence numbers we can keep track of.  Change 128
  242.  * to 8192 for complete accuracy...
  243.  */
  244. #define    MAX_DUP_CHK    (8 * 128)
  245. unsigned short mx_dup_ck = MAX_DUP_CHK;
  246. typedef char duptable[MAX_DUP_CHK / 8];
  247.  
  248. unsigned short icmpseq = 0;    /* Sequence number of last packet we sent */
  249.  
  250. int datalen_small = DEFDATALEN_SMALL;
  251. int datalen_big = DEFDATALEN_BIG;
  252. int datalen_step;
  253. int bits;
  254.  
  255. /* From packet len, compute the index for the entry */
  256.  
  257. #define    datalen_to_index(len)    ((len) == datalen_big    \
  258.                     ? nts-1        \
  259.                     : ((len)-datalen_small)/datalen_step)
  260.  
  261. #define    datalen_check(len) ((len) >= datalen_small    \
  262.                 && (len) <= datalen_big    \
  263.                 && (((len) == datalen_big    \
  264.                 || ((len)-datalen_small) % datalen_step == 0)))
  265.  
  266. icmp_handle my_icmp;        /* ICMP module handle */
  267.  
  268. u_char outpack[MAXPACKET];
  269.  
  270. /* counters */
  271. long npackets = 1;        /* max sampling loops */
  272. long nsamples;            /* max samples to take in a loop */
  273. int maxwait = 4;        /* max wait for reply packet (seconds) */
  274.  
  275. FILE *samplefile = NULL;
  276.  
  277. /* timing */
  278.  
  279. struct dst {
  280.     /* RTT statistics in ms */
  281.     double tmin;            /* minimum */
  282.     double tmax;            /* maximum */
  283.     double tsum;            /* sum */
  284.     double tsum2;            /* sum of squares */
  285.     long nsamples;            /* number of samples */
  286. };
  287.  
  288. #define    dst_newsample(dst,s) { \
  289.     if ((s) < (dst)->tmin) (dst)->tmin = (s); \
  290.     if ((s) > (dst)->tmax) (dst)->tmax = (s); \
  291.     (dst)->tsum += (s); \
  292.     (dst)->tsum2 += (s)*(s); \
  293.     (dst)->nsamples++; \
  294. }
  295.  
  296. #define dst_init(dst) { \
  297.     (dst)->tmin = (double)LONG_MAX; \
  298.     (dst)->tmax = 0.0; \
  299.     (dst)->tsum = 0.0; \
  300.     (dst)->tsum2 = 0.0; \
  301.     (dst)->nsamples = 0; \
  302. }
  303.  
  304. #define dst_min(dst)    ((dst)->tmin)
  305. #define dst_max(dst)    ((dst)->tmax)
  306. #define dst_avg(dst)    ((dst)->nsamples ? (dst)->tsum/(dst)->nsamples : 0.0)
  307.  
  308. struct timestats {
  309.     /* Time stats */
  310.     struct dst rttstats;        /* round trip time stats */
  311.                     /* including # of packets we got back */
  312. #define    nreceived rttstats.nsamples
  313.     long nrepeats;            /* number of duplicates */
  314.     long ntransmitted;        /* number of packets sent */
  315. };
  316.  
  317. #define ts_init(ts)    \
  318.     dst_init(&(ts)->rttstats);    \
  319.     (ts)->nrepeats = (ts)->ntransmitted = 0;
  320.  
  321. struct hoststats {
  322.     /* Host info */
  323.     char hnamebuf[MAXHOSTNAMELEN];
  324.     char *hostname;
  325.     struct sockaddr_in whereto;
  326.     struct sockaddr_in *to;
  327.     struct timestats *ts;
  328. };
  329.  
  330. duptable rcvd_tbl;        /* bit array for duplicate replies detection */
  331.  
  332. struct hoststats *phs;
  333. int nhosts;
  334.  
  335. struct timestats *pts;
  336. int nts = 2;
  337.  
  338. /* volatile */ char exit_flag = 0;
  339.  
  340. /* Compute variance */
  341.  
  342. double dst_var(dst)
  343.     struct dst *dst;
  344. {
  345.     if (dst->nsamples > 1)
  346.     return (dst->tsum2 - (dst->tsum * dst->tsum / dst->nsamples))
  347.         / (dst->nsamples-1);
  348.     else
  349.     return 0.0;
  350. }
  351.  
  352. /* Compute standard deviation */
  353.  
  354. double dst_stddev(dst)
  355.     struct dst *dst;
  356. {
  357.     double v = dst_var(dst);
  358.     if (dst->nsamples > 1 && v > 0)
  359.     return (double) sqrt(v);
  360.     else
  361.     return 0.0;
  362. }
  363.  
  364. void set_ip(hs, target)
  365.     struct hoststats *hs;
  366.     char *target;
  367. {
  368.     struct hostent *hp;
  369.  
  370.     hs->to = &hs->whereto;
  371.  
  372.     memset((char *)hs->to, 0, sizeof(struct sockaddr_in));
  373.     hs->to->sin_family = AF_INET;
  374.     hs->to->sin_addr.s_addr = inet_addr(target);
  375.     if (hs->to->sin_addr.s_addr != (u_int)-1)
  376.         hs->hostname = target;
  377.     else {
  378.         hp = gethostbyname(target);
  379.         if (!hp) {
  380.             (void)fprintf(stderr,
  381.                 "bing: unknown host %s\n", target);
  382.             exit(1);
  383.         }
  384.         hs->to->sin_family = hp->h_addrtype;
  385.         memcpy((caddr_t)&hs->to->sin_addr, hp->h_addr, hp->h_length);
  386.         strncpy(hs->hnamebuf, hp->h_name, sizeof(hs->hnamebuf) - 1);
  387.         hs->hnamebuf[sizeof(hs->hnamebuf)-1] = '\0';
  388.         hs->hostname = hs->hnamebuf;
  389.     }
  390. }
  391.  
  392. void randomfill(bp, len, seed)
  393.     char *bp;
  394.     int len;
  395.     long seed;
  396. {
  397.     /* Initialise the packet payload with random data.
  398.      * Note that on some platforms (e.g. Win32) RAND_MAX is less
  399.      * than INT_MAX. Thus we only use the lower byte of the returned
  400.      * int which in turn relies on the assumption that RAND_MAX+1
  401.      * is a power of 2. Fortunately this seems to always be the 
  402.      * case.
  403.      */
  404.     srandom((unsigned)seed);
  405.     while (len > 0) {
  406.         *bp++ = (char)(random() & 0xff);
  407.         len--;
  408.     }
  409. }
  410.  
  411. static long lastrand;
  412. static char nrand;
  413.  
  414. void randominit(seed)
  415.     long seed;
  416. {
  417.     srandom((unsigned)seed);
  418.     nrand = 0;
  419. }
  420.  
  421. u_char randomnext()
  422. {
  423.     u_char r;
  424.     if (nrand-- == 0) {
  425.         lastrand = random();
  426.         nrand = 3;
  427.     }
  428.     r = lastrand >> 24;
  429.     lastrand <<= 8;
  430.     return r;
  431. }
  432.  
  433. /*
  434.  * pinger --
  435.  *     Compose and transmit an ICMP ECHO REQUEST packet.  The IP packet
  436.  * will be added on by the kernel.  The ID field is our UNIX process ID,
  437.  * and the sequence number is an ascending integer.
  438.  */
  439. void pinger(hs, datalen)
  440.     struct hoststats *hs;
  441.     int datalen;
  442. {
  443.     struct timestats *ts;
  444.     register struct icmp *icp;
  445.     register int cc;
  446.     int i;
  447.  
  448.     ts = hs->ts + datalen_to_index(datalen);
  449.  
  450.     icp = (struct icmp *)outpack;
  451.     icp->icmp_type = ICMP_ECHO;
  452.     icp->icmp_code = 0;
  453.     icp->icmp_seq = ++icmpseq;
  454.  
  455.     /* icmp_id and icmp_cksum will be filled-in by icmp_send() */
  456.  
  457.     ts->ntransmitted++;
  458.  
  459.     CLR(icp->icmp_seq % mx_dup_ck, rcvd_tbl);
  460.  
  461.     if (options & F_RANDOMFILL)
  462.         randomfill((long *)(outpack + 8), datalen,
  463.                icp->icmp_seq);
  464.  
  465.     cc = datalen + 8;            /* skips ICMP portion */
  466.  
  467.     i = icmp_send(my_icmp,
  468.         (char *)outpack, cc, 
  469.         (struct sockaddr *)hs->to, sizeof(struct sockaddr));
  470.  
  471.     if (i < 0 || i != cc)  {
  472.         if (i < 0)
  473.             perror("icmp_send");
  474.         (void)printf("bing: wrote %s %d chars, ret=%d\n",
  475.             hs->hostname, cc, i);
  476.     }
  477. }
  478.  
  479. /*
  480.  * pr_iph --
  481.  *    Print an IP header with options.
  482.  */
  483. void pr_iph(ip)
  484.     struct ip *ip;
  485. {
  486.     int hlen;
  487.     u_char *cp;
  488.  
  489.     hlen = ip->ip_hl << 2;
  490.     cp = (u_char *)ip + 20;        /* point to options */
  491.  
  492.     (void)printf("Vr HL TOS  Len   ID Flg  off TTL Pro  cks      Src      Dst Data\n");
  493.     (void)printf(" %1x  %1x  %02x %04x %04x",
  494.         ip->ip_v, ip->ip_hl, ip->ip_tos, ip->ip_len, ip->ip_id);
  495.     (void)printf("   %1x %04x", ((ip->ip_off) & 0xe000) >> 13,
  496.         (ip->ip_off) & 0x1fff);
  497.     (void)printf("  %02x  %02x %04x", ip->ip_ttl, ip->ip_p, ip->ip_sum);
  498. #ifndef linux
  499.     (void)printf(" %s ", inet_ntoa(*(struct in_addr *)&ip->ip_src.s_addr));
  500.     (void)printf(" %s ", inet_ntoa(*(struct in_addr *)&ip->ip_dst.s_addr));
  501. #else
  502.     (void)printf(" %s ", inet_ntoa(*(struct in_addr *)&ip->ip_src));
  503.     (void)printf(" %s ", inet_ntoa(*(struct in_addr *)&ip->ip_dst));
  504. #endif
  505.     /* dump any option bytes */
  506.     while (hlen-- > 20) {
  507.         (void)printf("%02x", *cp++);
  508.     }
  509.     (void)putchar('\n');
  510. }
  511.  
  512. /*
  513.  * pr_retip --
  514.  *    Dump some info on a returned (via ICMP) IP packet.
  515.  */
  516. void pr_retip(ip)
  517.     struct ip *ip;
  518. {
  519.     int hlen;
  520.     u_char *cp;
  521.  
  522.     pr_iph(ip);
  523.     hlen = ip->ip_hl << 2;
  524.     cp = (u_char *)ip + hlen;
  525.  
  526.     if (ip->ip_p == 6)
  527.         (void)printf("TCP: from port %u, to port %u (decimal)\n",
  528.             (*cp * 256 + *(cp + 1)), (*(cp + 2) * 256 + *(cp + 3)));
  529.     else if (ip->ip_p == 17)
  530.         (void)printf("UDP: from port %u, to port %u (decimal)\n",
  531.             (*cp * 256 + *(cp + 1)), (*(cp + 2) * 256 + *(cp + 3)));
  532. }
  533.  
  534. #ifdef notdef
  535. static char *ttab[] = {
  536.     "Echo Reply",        /* ip + seq + udata */
  537.     "Dest Unreachable",    /* net, host, proto, port, frag, sr + IP */
  538.     "Source Quench",    /* IP */
  539.     "Redirect",        /* redirect type, gateway, + IP  */
  540.     "Echo",
  541.     "Time Exceeded",    /* transit, frag reassem + IP */
  542.     "Parameter Problem",    /* pointer + IP */
  543.     "Timestamp",        /* id + seq + three timestamps */
  544.     "Timestamp Reply",    /* " */
  545.     "Info Request",        /* id + sq */
  546.     "Info Reply"        /* " */
  547. };
  548. #endif
  549.  
  550. /*
  551.  * pr_icmph --
  552.  *    Print a descriptive string about an ICMP header.
  553.  */
  554. void pr_icmph(icp)
  555.     struct icmp *icp;
  556. {
  557.     switch(icp->icmp_type) {
  558.     case ICMP_ECHOREPLY:
  559.         (void)printf("Echo Reply\n");
  560.         /* XXX ID + Seq + Data */
  561.         break;
  562.     case ICMP_UNREACH:
  563.         switch(icp->icmp_code) {
  564.         case ICMP_UNREACH_NET:
  565.             (void)printf("Destination Net Unreachable\n");
  566.             break;
  567.         case ICMP_UNREACH_HOST:
  568.             (void)printf("Destination Host Unreachable\n");
  569.             break;
  570.         case ICMP_UNREACH_PROTOCOL:
  571.             (void)printf("Destination Protocol Unreachable\n");
  572.             break;
  573.         case ICMP_UNREACH_PORT:
  574.             (void)printf("Destination Port Unreachable\n");
  575.             break;
  576.         case ICMP_UNREACH_NEEDFRAG:
  577.             (void)printf("frag needed and DF set\n");
  578.             break;
  579.         case ICMP_UNREACH_SRCFAIL:
  580.             (void)printf("Source Route Failed\n");
  581.             break;
  582.         default:
  583.             (void)printf("Dest Unreachable, Bad Code: %d\n",
  584.                 icp->icmp_code);
  585.             break;
  586.         }
  587.         /* Print returned IP header information */
  588.         pr_retip((struct ip *)ICMP_TO_DATA(icp));
  589.         break;
  590.     case ICMP_SOURCEQUENCH:
  591.         (void)printf("Source Quench\n");
  592.         pr_retip((struct ip *)ICMP_TO_DATA(icp));
  593.         break;
  594.     case ICMP_REDIRECT:
  595.         switch(icp->icmp_code) {
  596.         case ICMP_REDIRECT_NET:
  597.             (void)printf("Redirect Network");
  598.             break;
  599.         case ICMP_REDIRECT_HOST:
  600.             (void)printf("Redirect Host");
  601.             break;
  602.         case ICMP_REDIRECT_TOSNET:
  603.             (void)printf("Redirect Type of Service and Network");
  604.             break;
  605.         case ICMP_REDIRECT_TOSHOST:
  606.             (void)printf("Redirect Type of Service and Host");
  607.             break;
  608.         default:
  609.             (void)printf("Redirect, Bad Code: %d", icp->icmp_code);
  610.             break;
  611.         }
  612.         (void)printf("(New addr: 0x%08lx)\n",
  613.             (unsigned long)icp->icmp_gwaddr.s_addr);
  614.         pr_retip((struct ip *)ICMP_TO_DATA(icp));
  615.         break;
  616.     case ICMP_ECHO:
  617.         (void)printf("Echo Request\n");
  618.         /* XXX ID + Seq + Data */
  619.         break;
  620.     case ICMP_TIMXCEED:
  621.         switch(icp->icmp_code) {
  622.         case ICMP_TIMXCEED_INTRANS:
  623.             (void)printf("Time to live exceeded\n");
  624.             break;
  625.         case ICMP_TIMXCEED_REASS:
  626.             (void)printf("Frag reassembly time exceeded\n");
  627.             break;
  628.         default:
  629.             (void)printf("Time exceeded, Bad Code: %d\n",
  630.                 icp->icmp_code);
  631.             break;
  632.         }
  633.         pr_retip((struct ip *)ICMP_TO_DATA(icp));
  634.         break;
  635.     case ICMP_PARAMPROB:
  636.         (void)printf("Parameter problem: pointer = 0x%02x\n",
  637.             icp->icmp_hun.ih_pptr);
  638.         pr_retip((struct ip *)ICMP_TO_DATA(icp));
  639.         break;
  640.     case ICMP_TSTAMP:
  641.         (void)printf("Timestamp\n");
  642.         /* XXX ID + Seq + 3 timestamps */
  643.         break;
  644.     case ICMP_TSTAMPREPLY:
  645.         (void)printf("Timestamp Reply\n");
  646.         /* XXX ID + Seq + 3 timestamps */
  647.         break;
  648.     case ICMP_IREQ:
  649.         (void)printf("Information Request\n");
  650.         /* XXX ID + Seq */
  651.         break;
  652.     case ICMP_IREQREPLY:
  653.         (void)printf("Information Reply\n");
  654.         /* XXX ID + Seq */
  655.         break;
  656. #ifdef ICMP_MASKREQ
  657.     case ICMP_MASKREQ:
  658.         (void)printf("Address Mask Request\n");
  659.         break;
  660. #endif
  661. #ifdef ICMP_MASKREPLY
  662.     case ICMP_MASKREPLY:
  663.         (void)printf("Address Mask Reply\n");
  664.         break;
  665. #endif
  666.     default:
  667.         (void)printf("Bad ICMP type: %d\n", icp->icmp_type);
  668.     }
  669. }
  670.  
  671. /*
  672.  * pr_addr --
  673.  *    Return an ascii host address as a dotted quad and optionally with
  674.  *      a hostname.
  675.  */
  676. char *
  677. pr_addr(l)
  678.     u_long l;
  679. {
  680.     struct hostent *hp;
  681.     static char buf[80];
  682.  
  683.     if ((options & F_NUMERIC) ||
  684.         !(hp = gethostbyaddr((char *)&l, 4, AF_INET)))
  685.         (void)snprintf(snfargs(buf, sizeof(buf), "%s"), 
  686.                inet_ntoa(*(struct in_addr *)&l));
  687.     else
  688.         (void)snprintf(snfargs(buf, sizeof(buf), "%s (%s)"),
  689.                hp->h_name,
  690.                inet_ntoa(*(struct in_addr *)&l));
  691.     return(buf);
  692. }
  693.  
  694. /*
  695.  * pr_pack --
  696.  *    Print out the packet, if it came from us.  This logic is necessary
  697.  * because ALL readers of the ICMP socket get a copy of ALL ICMP packets
  698.  * which arrive ('tis only fair).  This permits multiple copies of this
  699.  * program to be run without having intermingled output (or statistics!).
  700.  */
  701. int pr_pack(buf, cc, from, elapsed)
  702.     char *buf;
  703.     int cc;
  704.     struct sockaddr_in *from;
  705.     double elapsed;
  706. {
  707.     struct timestats *ts;
  708.     struct hoststats *hs;
  709.  
  710.     register struct icmp *icp;
  711.     register u_long l;
  712.     register int hn, i, j;
  713.     register u_char *cp,*dp;
  714.     u_char d;
  715.     static int old_rrlen;
  716.     static char old_rr[MAX_IPOPTLEN];
  717.     struct ip *ip;
  718.     int hlen, dupflag;
  719.     int bcc = cc;
  720.  
  721.     /* ip header */
  722.     ip = (struct ip *)buf;
  723.     hlen = ip->ip_hl << 2;
  724.     /* icmp header */
  725.     bcc -= hlen;
  726.     icp = (struct icmp *)(buf + hlen);
  727.  
  728.         /* Look for the source host in our list */
  729.     hs = NULL;
  730.  
  731.     for (hn = 0; hn < nhosts; hn++) {
  732.         if (from->sin_addr.s_addr == phs[hn].to->sin_addr.s_addr) {
  733.         hs = phs+hn;
  734.         break;
  735.         }
  736.     }
  737.  
  738.     if (hs == NULL) {
  739.         /*
  740.          * Never heard about this host...
  741.          * Can either be an unexpected reply to one of our packets,
  742.          * or a reply to somebody else (another ping/bing running on
  743.          * the same host as we do, for example).
  744.          * The best is to ignore it.
  745.          */
  746.         return -1;
  747.     }
  748.     if (!datalen_check(cc - 28)) {
  749.         if (!(options & F_VERBOSE))
  750.         return -1;
  751.         (void)fprintf(stderr,
  752.           "bing: unexpected packet size (%d bytes) from %s\n", cc,
  753.           inet_ntoa(*(struct in_addr *)&from->sin_addr.s_addr));
  754.         pr_icmph(icp);
  755.     } else {
  756.         ts = &hs->ts[datalen_to_index(cc - 28)];
  757.     }
  758.  
  759.     /* Check the IP header */
  760.     if (bcc < ICMP_MINLEN) {
  761.         if (!(options & F_VERBOSE))
  762.             return -1;
  763.         (void)fprintf(stderr,
  764.           "bing: packet too short (%d bytes) from %s\n", cc,
  765.           inet_ntoa(*(struct in_addr *)&from->sin_addr.s_addr));
  766.     }
  767.  
  768.     /* Now the ICMP part */
  769.     if (icp->icmp_type == ICMP_ECHOREPLY) {
  770.         if (icp->icmp_id != icmp_get_id(my_icmp))
  771.             return -1;            /* 'Twas not our ECHO */
  772.         if (icp->icmp_seq == icmpseq) {
  773.            /*
  774.             * This is the last packet we sent,
  775.             * 'elapsed' is the rtt.
  776.             */
  777.            dst_newsample(&ts->rttstats, elapsed);
  778.  
  779.            if (samplefile) {
  780.               fprintf(samplefile, "%d\t%d\t%.3f\n",
  781.                   hn, cc, elapsed);
  782.            }
  783.         }
  784.  
  785.         if (TST(icp->icmp_seq % mx_dup_ck, rcvd_tbl)) {
  786.             ++(ts->nrepeats);
  787.             dupflag = 1;
  788.         } else {
  789.             SET(icp->icmp_seq % mx_dup_ck, rcvd_tbl);
  790.             dupflag = 0;
  791.         }
  792.  
  793.         if (!(options & F_VVERBOSE))
  794.             return 0;
  795.  
  796.         (void)printf("%d bytes from %s: icmp_seq=%u", cc,
  797.            inet_ntoa(*(struct in_addr *)&from->sin_addr.s_addr),
  798.            icp->icmp_seq);
  799.         (void)printf(" ttl=%d", ip->ip_ttl);
  800.         (void)printf(" time=%.3f ms", elapsed);
  801.         if (dupflag)
  802.             (void)printf(" (DUP!)");
  803.         /* check the data */
  804.         cp = ICMP_TO_DATA(icp);
  805.         if (options & F_RANDOMFILL) {
  806.             randominit(icp->icmp_seq);
  807.         } else {
  808.             dp = &outpack[8];
  809.         }
  810.         for (i = 8; i < cc; ++i, ++cp, ++dp) {
  811.             if (options & F_RANDOMFILL) {
  812.                 d = randomnext();
  813.             } else {
  814.                 d = *dp;
  815.             }
  816.             if (*cp != d) {
  817.     (void)printf("\nwrong data byte #%d should be 0x%x but was 0x%x",
  818.             i, d, *cp);
  819.                 cp = ICMP_TO_DATA(icp);
  820.                 for (i = 8; i < cc; ++i, ++cp) {
  821.                     if ((i % 32) == 8)
  822.                         (void)printf("\n\t");
  823.                     (void)printf("%x ", *cp);
  824.                 }
  825.                 break;
  826.             }
  827.         }
  828.     } else {
  829.         /* We've got something other than an ECHOREPLY */
  830.         if (!(options & F_VERBOSE))
  831.             return -1;
  832.         (void)printf("%d bytes from %s: ", cc,
  833.             pr_addr(from->sin_addr.s_addr));
  834.             pr_icmph(icp);
  835.     }
  836.  
  837.     /* Display any IP options */
  838.     cp = (u_char *)buf + sizeof(struct ip);
  839.  
  840.     for (; hlen > (int)sizeof(struct ip); --hlen, ++cp)
  841.         switch (*cp) {
  842.         case IPOPT_EOL:
  843.             hlen = 0;
  844.             break;
  845.         case IPOPT_LSRR:
  846.             (void)printf("\nLSRR: ");
  847.             hlen -= 2;
  848.             j = *++cp;
  849.             ++cp;
  850.             if (j > IPOPT_MINOFF)
  851.                 for (;;) {
  852.                     l = *++cp;
  853.                     l = (l<<8) + *++cp;
  854.                     l = (l<<8) + *++cp;
  855.                     l = (l<<8) + *++cp;
  856.                     if (l == 0)
  857.                         (void)printf("\t0.0.0.0");
  858.                 else
  859.                     (void)printf("\t%s", pr_addr(ntohl(l)));
  860.                 hlen -= 4;
  861.                 j -= 4;
  862.                 if (j <= IPOPT_MINOFF)
  863.                     break;
  864.                 (void)putchar('\n');
  865.             }
  866.             break;
  867.         case IPOPT_RR:
  868.             j = *++cp;        /* get length */
  869.             i = *++cp;        /* and pointer */
  870.             hlen -= 2;
  871.             if (i > j)
  872.                 i = j;
  873.             i -= IPOPT_MINOFF;
  874.             if (i <= 0)
  875.                 continue;
  876.             if (i == old_rrlen
  877.                 && cp == (u_char *)buf + sizeof(struct ip) + 2
  878.                 && !memcmp((char *)cp, old_rr, i)) {
  879.                 (void)printf("\t(same route)");
  880.                 i = ((i + 3) / 4) * 4;
  881.                 hlen -= i;
  882.                 cp += i;
  883.                 break;
  884.             }
  885.             old_rrlen = i;
  886.             memcpy(old_rr, (char *)cp, i);
  887.             (void)printf("\nRR: ");
  888.             for (;;) {
  889.                 l = *++cp;
  890.                 l = (l<<8) + *++cp;
  891.                 l = (l<<8) + *++cp;
  892.                 l = (l<<8) + *++cp;
  893.                 if (l == 0)
  894.                     (void)printf("\t0.0.0.0");
  895.                 else
  896.                     (void)printf("\t%s", pr_addr(ntohl(l)));
  897.                 hlen -= 4;
  898.                 i -= 4;
  899.                 if (i <= 0)
  900.                     break;
  901.                 (void)putchar('\n');
  902.             }
  903.             break;
  904.         case IPOPT_NOP:
  905.             (void)printf("\nNOP");
  906.             break;
  907.         default:
  908.             (void)printf("\nunknown option %x", *cp);
  909.             break;
  910.         }
  911.     (void)putchar('\n');
  912.     (void)fflush(stdout);
  913.     return 0;
  914. }
  915.  
  916. void ping_and_wait(hs, datalen, buf, buflen)
  917.     struct hoststats *hs;
  918.     int datalen;
  919.     char *buf;
  920.     int buflen;
  921. {
  922.     struct sockaddr_in from;
  923.     int fromlen;
  924.     int cc;
  925.     struct timestats *ts;
  926.     double elapsed;
  927.  
  928.     ts = hs->ts + datalen_to_index(datalen);
  929.     fromlen = sizeof(from);
  930.  
  931.     pinger(hs, datalen);
  932.  
  933.     for (;;) {
  934.  
  935.         /* Now read the reply packet */
  936.         cc = icmp_recv(my_icmp, buf, buflen,
  937.                  (struct sockaddr *)&from, &fromlen,
  938.                  &elapsed);
  939.  
  940.         if (cc > 0) {
  941.            /* Print and exit if OK */
  942.            if (pr_pack((char *)buf, cc, &from, elapsed) == 0) {
  943.           break;
  944.            }
  945.         } else if (cc == 0) {
  946.         /* Time out */
  947.         break;
  948.         } else if (exit_flag) {
  949.         ts->ntransmitted--;
  950.         break;
  951.         }
  952.     }
  953. }
  954.  
  955. void warn_rtt(h1, h2, min1s, min1b, min2s, min2b)
  956.     char *h1, *h2;
  957.     double min1s, min1b, min2s, min2b;
  958. {
  959.     double deltab, deltas;
  960.     char *pmsg = (options & F_PEDANTIC) ? " (ignored)" : "";
  961.  
  962.     /* Small packet rtts should be < big packet rtts */
  963.     if (min1b < min1s)
  964.         fprintf(stderr,
  965.             "warning: rtt big %s %.3fms < rtt small %s %.3fms%s\n",
  966.             h1, min1b, h1, min1s, pmsg);
  967.     if (min2b < min2s)
  968.         fprintf(stderr,
  969.             "warning: rtt big %s %.3fms < rtt small %s %.3fms%s\n",
  970.             h2, min2b, h2, min2s, pmsg);
  971.  
  972.     /* rtts to host1 should be < rtts to host2 */
  973.     if (min1s > min2s)
  974.         fprintf(stderr,
  975.             "warning: rtt small %s %.3fms > rtt small %s %.3fms%s\n",
  976.             h1, min1s, h2, min2s, pmsg);
  977.     if (min1b > min2b)
  978.         fprintf(stderr,
  979.             "warning: rtt big %s %.3fms > rtt big %s %.3fms%s\n",
  980.             h1, min1b, h2, min2b, pmsg);
  981.  
  982.     /* Delta on small packets should be < delta on big packets */
  983.     deltab = min2b - min1b;
  984.     deltas = min2s - min1s;
  985.     if (deltab < deltas)
  986.         fprintf(stderr,
  987.             "warning: %s to %s delta big rtts %.3fms < delta small rtts %.3fms%s\n",
  988.             h1, h2, deltab, deltas, pmsg);
  989. }
  990.  
  991. /* Sanity checks and corrections for rtts */
  992.  
  993. void adapt_rtt(min1s, min1b, min2s, min2b)
  994.     double *min1s, *min1b, *min2s, *min2b;
  995. {
  996.     double deltab, deltas;
  997.  
  998.     /* Don't correct anything if pedantic mode */
  999.     if (options & F_PEDANTIC)
  1000.         return;
  1001.  
  1002.     /* Small packet rtts should be < big packet rtts */
  1003.     if (*min1b < *min1s) *min1s = *min1b;
  1004.     if (*min2b < *min2s) *min2s = *min2b;
  1005.  
  1006.     /* rtts to host1 should be < rtts to host2 */
  1007.     if (*min1s > *min2s) *min2s = *min1s;
  1008.     if (*min1b > *min2b) *min2b = *min1b;
  1009.  
  1010.     /* Delta on small packets should be < delta on big packets */
  1011.     deltab = *min2b - *min1b;
  1012.     deltas = *min2s - *min1s;
  1013.     if (deltab < deltas) {
  1014.         *min2s = *min2b;
  1015.         *min1s = *min1b;
  1016.     }
  1017. }
  1018.  
  1019. void
  1020. finishpa(ntransmitted, received, nrepeats, vmin, vavg, vmax, vsd)
  1021.     long ntransmitted, received, nrepeats;
  1022.     double vmin, vavg, vmax, vsd;
  1023. {
  1024.     /* XXX: float a; */
  1025.  
  1026.     (void)printf("%6ld%6ld", ntransmitted, received - nrepeats);
  1027.     if (nrepeats)
  1028.         (void)printf("%6ld", nrepeats);
  1029.     else
  1030.         (void)printf("      ");
  1031.     if (ntransmitted)
  1032.         if (received - nrepeats > ntransmitted)
  1033.             (void)printf("  ****\t");
  1034.         else
  1035.             (void)printf("%5d%%\t",
  1036.                 (int) (((ntransmitted - received + nrepeats)
  1037.                 * 100) /
  1038.                 ntransmitted));
  1039.     else
  1040.         (void)printf("      \t");
  1041.     if (received - nrepeats)
  1042.         (void)printf("    %9.3f %9.3f %9.3f %9.3f\n",
  1043.             vmin,
  1044.             vavg,
  1045.             vmax,
  1046.             vsd);
  1047.     else
  1048.         (void)putchar('\n');
  1049. }
  1050.  
  1051. #define finishp(ts) finishpa((ts)->ntransmitted,        \
  1052.                  (ts)->nreceived,            \
  1053.                  (ts)->nrepeats,            \
  1054.                  dst_min(&(ts)->rttstats),        \
  1055.                  dst_avg(&(ts)->rttstats),        \
  1056.                  dst_max(&(ts)->rttstats),        \
  1057.                  dst_stddev(&(ts)->rttstats))
  1058.  
  1059. /*
  1060.  * finish --
  1061.  *    Print out ping statistics for one host
  1062.  */
  1063.  
  1064. void finish(hs)
  1065.     struct hoststats *hs;
  1066. {
  1067.     int j;
  1068.  
  1069.     (void)putchar('\n');
  1070.     (void)printf("--- %s statistics ---\n", hs->hostname);
  1071.     (void)printf(
  1072. "bytes   out    in   dup  loss\trtt (ms): min       avg       max   std dev\n");
  1073.  
  1074.     for (j = 0; j < nts; j++) {
  1075.         (void)printf("%5d", j+1 == nts ? datalen_big
  1076.                        : datalen_small + j*datalen_step);
  1077.         finishp(&hs->ts[j]);
  1078.     }
  1079. }
  1080.  
  1081. void finishit()
  1082. {
  1083.     double secs;
  1084.     double maxthru;
  1085.     double mindel;
  1086.     double rtt1s, rtt1b, rtt2s, rtt2b;
  1087.     struct hoststats *hs1, *hs2;
  1088.  
  1089.     int i;
  1090.  
  1091.     for (i = 0; i < nhosts; i++) {
  1092.         hs2 = phs+i;
  1093.         finish(hs2);
  1094.     }
  1095.  
  1096.     printf("\n--- estimated link characteristics ---\n");
  1097.     printf("host\t\t\t          bandwidth       ms\n");
  1098.  
  1099.     for (i = 1; i < nhosts; i++) {
  1100.         hs1 = phs+i-1;
  1101.         hs2 = phs+i;
  1102.  
  1103.         if (hs1->ts[nts-1].nreceived == 0
  1104.         || hs1->ts[0].nreceived == 0
  1105.         || hs2->ts[nts-1].nreceived == 0
  1106.         || hs2->ts[0].nreceived == 0) {
  1107.  
  1108.         (void)printf("%s: not enough received packets\n",
  1109.                  hs2->hostname);
  1110.         continue;
  1111.         }
  1112.  
  1113.         rtt1s = dst_min(&hs1->ts[0].rttstats);
  1114.         rtt1b = dst_min(&hs1->ts[nts-1].rttstats);
  1115.         rtt2s = dst_min(&hs2->ts[0].rttstats);
  1116.         rtt2b = dst_min(&hs2->ts[nts-1].rttstats);
  1117.         warn_rtt(hs1->hostname, hs2->hostname,
  1118.              rtt1s, rtt1b, rtt2s, rtt2b);
  1119.         adapt_rtt(&rtt1s, &rtt1b, &rtt2s, &rtt2b);
  1120.         secs = (rtt2b - rtt1b) - (rtt2s - rtt1s);
  1121.  
  1122.         if (secs == 0) {
  1123.         (void)printf(
  1124. "%s: minimum delay difference is zero, can't estimate link throughput.\n",
  1125.             hs2->hostname);
  1126.         continue;
  1127.         }
  1128.  
  1129.         maxthru = bits / secs * 1e3;
  1130.         mindel = (dst_min(&hs2->ts[0].rttstats)
  1131.               - dst_min(&hs1->ts[0].rttstats))
  1132.         - (datalen_small * (8*2)) / maxthru;
  1133.         if (maxthru<1e3)
  1134.             printf("%-32s    %6.3fbps    %9.3f\n",
  1135.             hs2->hostname, maxthru, mindel);
  1136.         else if (maxthru>1e6)
  1137.             printf("%-32s    %6.3fMbps   %9.3f\n",
  1138.             hs2->hostname, maxthru/1e6, mindel);
  1139.         else
  1140.             printf("%-32s    %6.3fKbps   %9.3f\n",
  1141.             hs2->hostname, maxthru/1e3, mindel);
  1142.  
  1143.     }
  1144.     return;
  1145. }
  1146.  
  1147. /* Flag for exit as soon as possible */
  1148. void finishit_exit()
  1149. {
  1150.     exit_flag = 1;
  1151. }
  1152.  
  1153. /* Fill the packet with the provided pattern */
  1154. void fill(bp, patp)
  1155.     char *bp, *patp;
  1156. {
  1157.     register int ii, jj, kk;
  1158.     int pat[16];
  1159.     char *cp;
  1160.  
  1161.     for (cp = patp; *cp; cp++)
  1162.         if (!isxdigit(*cp)) {
  1163.             (void)fprintf(stderr,
  1164.                 "bing: patterns must be specified as hex digits.\n");
  1165.             exit(1);
  1166.         }
  1167.     ii = sscanf(patp,
  1168.         "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
  1169.         &pat[0], &pat[1], &pat[2], &pat[3], &pat[4], &pat[5], &pat[6],
  1170.         &pat[7], &pat[8], &pat[9], &pat[10], &pat[11], &pat[12],
  1171.         &pat[13], &pat[14], &pat[15]);
  1172.  
  1173.     if (ii > 0)
  1174.         for (kk = 0; kk <= MAXPACKET - (8 + ii); kk += ii)
  1175.             for (jj = 0; jj < ii; ++jj)
  1176.                 bp[jj + kk] = pat[jj];
  1177.     if (options & F_VVERBOSE) {
  1178.         (void)printf("PATTERN: 0x");
  1179.         for (jj = 0; jj < ii; ++jj)
  1180.             (void)printf("%02x", bp[jj] & 0xFF);
  1181.         (void)printf("\n");
  1182.     }
  1183. }
  1184.  
  1185. void usage()
  1186. {
  1187.     (void)fprintf(stderr,
  1188.         "usage: bing [-dDnrRPvVwz] [-c count] [-e samples] [-i wait]\n\t[-p pattern] [-s small packetsize] [-S big packetsize]\n\t[-u size increment] [-t ttl] [-I interface address]\n\t[-f sample file] host1 host2...\n");
  1189.     exit(1);
  1190. }
  1191.  
  1192. #ifdef WIN32
  1193. BOOL PASCAL ConsoleCtrlHandler(DWORD dwCtrlType)
  1194. {
  1195.     if (dwCtrlType==CTRL_C_EVENT) {
  1196.         finishit_exit();
  1197.         return TRUE;
  1198.     } else
  1199.         return FALSE;
  1200. }
  1201. #endif
  1202.  
  1203. int main(argc, argv)
  1204.     int argc;
  1205.     char **argv;
  1206. {
  1207.     extern int optind;
  1208.     extern char *optarg;
  1209.     struct in_addr ifaddr;
  1210.     int ntrans, nloops;
  1211.     int i, j;
  1212.     int ch, hold, recv_packlen;
  1213.     u_char *datap, *recv_packet;
  1214.     u_char ttl, loop;
  1215. #ifdef IP_OPTIONS
  1216.     char rspace[3 + 4 * NROUTES + 1];    /* record route space */
  1217. #endif
  1218.  
  1219. #ifdef WIN32
  1220.     {
  1221.         WSADATA wsaData;
  1222.         WORD wsaVersionRequested;
  1223.         int err;
  1224.  
  1225.         /* Initialise the winsock */
  1226.         wsaVersionRequested = MAKEWORD( 1, 1 );
  1227.         err = WSAStartup( wsaVersionRequested, &wsaData );
  1228.         if (err!=0) {
  1229.             fprintf(stderr,"bing: Could not initialise the winsock\n");
  1230.             exit(1);
  1231.         }
  1232.  
  1233.         /* Install the ^C handler */
  1234.         SetConsoleCtrlHandler(ConsoleCtrlHandler,TRUE);
  1235.  
  1236.         __progname=argv[0];
  1237.     }
  1238. #endif
  1239.  
  1240.     /*
  1241.      * Open our raw socket at once, then setuid() back to
  1242.      * the real uid as soon as possible (we have to, in
  1243.      * case the -f option is used, and it's better anyway for
  1244.      * obvious security reasons).
  1245.      */
  1246.     my_icmp = icmp_open();
  1247.     if (my_icmp == NULL) {
  1248.        fprintf(stderr, "cannot open ICMP module\n");
  1249.        exit(1);
  1250.     }
  1251.  
  1252. #ifndef WIN32
  1253.     setgid(getgid());
  1254.     setuid(getuid());
  1255. #endif
  1256.  
  1257.     datap = &outpack[8];
  1258.     while ((ch = getopt(argc, argv, "c:dDe:f:I:i:LnPp:RrS:s:t:u:vVwz")) != EOF)
  1259.         switch(ch) {
  1260.         case 'f':
  1261.             samplefile = fopen(optarg, "a");
  1262.             if (samplefile == NULL) {
  1263.                 (void)fprintf(stderr,
  1264.                     "bing: unable to open %s: ", optarg);
  1265.                 perror("");
  1266.                 exit(1);
  1267.             }
  1268.             break;
  1269.         case 'c':
  1270.             npackets = atoi(optarg);
  1271.             if (npackets <= 0) {
  1272.                 (void)fprintf(stderr,
  1273.                     "bing: bad number of packets to transmit.\n");
  1274.                 exit(1);
  1275.             }
  1276.             break;
  1277.         case 'D':
  1278.             options |= F_NODELTA;
  1279.             break;
  1280.         case 'P':
  1281.             options |= F_PEDANTIC;
  1282.             break;
  1283.         case 'w':
  1284.             options |= F_WARN;
  1285.             break;
  1286.         case 'd':
  1287.             options |= F_SO_DEBUG;
  1288.             break;
  1289.         case 'e':
  1290.             nsamples = atoi(optarg);
  1291.             if (nsamples <= 0) {
  1292.                 (void)fprintf(stderr,
  1293.                     "bing: bad number of samples.\n");
  1294.                 exit(1);
  1295.             }
  1296.             break;
  1297.         case 'i':        /* wait between sending packets */
  1298.             maxwait = atoi(optarg);
  1299.             if (maxwait <= 0) {
  1300.                 (void)fprintf(stderr,
  1301.                     "bing: bad maximum wait.\n");
  1302.                 exit(1);
  1303.             }
  1304.             options |= F_INTERVAL;
  1305.             break;
  1306.         case 'u':        /* packet size increment */
  1307.             datalen_step = atoi(optarg);
  1308.             if (datalen_step <= 0) {
  1309.                 (void)fprintf(stderr,
  1310.                     "bing: bad packet size increment.\n");
  1311.                 exit(1);
  1312.             }
  1313.             break;
  1314.         case 'n':
  1315.             options |= F_NUMERIC;
  1316.             break;
  1317.         case 'p':        /* fill buffer with user pattern */
  1318.             options |= F_PINGFILLED;
  1319.             fill((char *)datap, optarg);
  1320.             break;
  1321.         case 'V':
  1322.             options |= F_VVERBOSE;
  1323.             break;
  1324.         case 'R':
  1325.             options |= F_RROUTE;
  1326.             break;
  1327.         case 'r':
  1328.             options |= F_SO_DONTROUTE;
  1329.             break;
  1330.         case 'S':        /* size of big packet to send */
  1331.             datalen_big = atoi(optarg);
  1332.             if (datalen_big > MAXPACKET) {
  1333.                 (void)fprintf(stderr,
  1334.                     "bing: big packet size too large.\n");
  1335.                 exit(1);
  1336.             }
  1337.             if (datalen_big <= 0) {
  1338.                 (void)fprintf(stderr,
  1339.                     "bing: illegal big packet size.\n");
  1340.                 exit(1);
  1341.             }
  1342.             break;
  1343.         case 's':        /* size of small packet to send */
  1344.             datalen_small = atoi(optarg);
  1345.             if (datalen_small > MAXPACKET) {
  1346.                 (void)fprintf(stderr,
  1347.                     "bing: small packet size too large.\n");
  1348.                 exit(1);
  1349.             }
  1350.             if (datalen_small <= 0) {
  1351.                 (void)fprintf(stderr,
  1352.                     "bing: illegal small packet size.\n");
  1353.                 exit(1);
  1354.             }
  1355.             break;
  1356.         case 'v':
  1357.             options |= F_VERBOSE;
  1358.             break;
  1359.         case 'z':
  1360.             options |= F_RANDOMFILL;
  1361.             break;
  1362.         case 'L':
  1363.             moptions |= MULTICAST_NOLOOP;
  1364.             loop = 0;
  1365.             break;
  1366.         case 't':
  1367.             moptions |= MULTICAST_TTL;
  1368.             i = atoi(optarg);
  1369.             if (i < 0 || i > 255) {
  1370.                 printf("ttl %u out of range\n", i);
  1371.                 exit(1);
  1372.             }
  1373.             ttl = i;
  1374.             break;
  1375.         case 'I':
  1376.             moptions |= MULTICAST_IF;
  1377.             {
  1378.                 int i1, i2, i3, i4;
  1379.                 char dummy;
  1380.  
  1381.                 if (sscanf(optarg, "%u.%u.%u.%u%c",
  1382.                        &i1, &i2, &i3, &i4, &dummy) != 4) {
  1383.                     printf("bad interface address '%s'\n",
  1384.                            optarg);
  1385.                     exit(1);
  1386.                 }
  1387.                 ifaddr.s_addr = (i1<<24)|(i2<<16)|(i3<<8)|i4;
  1388.                 ifaddr.s_addr = htonl(ifaddr.s_addr);
  1389.             }
  1390.             break;
  1391.         default:
  1392.             usage();
  1393.         }
  1394.  
  1395.     if (datalen_small >= datalen_big) {
  1396.         (void)fprintf(stderr,
  1397.             "bing: small packet size >= big packet size\n");
  1398.         exit(1);
  1399.     }
  1400.  
  1401.     if (datalen_small < 0) {
  1402.         (void)fprintf(stderr,
  1403.             "bing: invalid packet size\n");
  1404.         exit(1);
  1405.     }
  1406.  
  1407.     bits = (datalen_big - datalen_small) * (8*2);
  1408.     if (datalen_step == 0 || datalen_small + datalen_step > datalen_big)
  1409.         datalen_step = datalen_big - datalen_small;
  1410.     nts = (datalen_big + datalen_step - 1 - datalen_small)/datalen_step + 1;
  1411.  
  1412.     argc -= optind;
  1413.     argv += optind;
  1414.     
  1415.     if (argc < 2)
  1416.         usage();
  1417.  
  1418.     icmp_set_timeout(my_icmp, maxwait*1000000);
  1419.  
  1420.     phs = (struct hoststats *)malloc(sizeof(struct hoststats) * argc);
  1421.     nhosts = argc;
  1422.  
  1423.     pts = (struct timestats *) malloc(sizeof(struct timestats)
  1424.                       * nts * nhosts);
  1425.     if (!phs || !pts) {
  1426.         (void)fprintf(stderr, "bing: out of memory.\n");
  1427.         exit(1);
  1428.     }
  1429.  
  1430.     for (i = 0; i < nhosts; i++) {
  1431.         set_ip(phs + i, argv[i]);
  1432.         phs[i].ts = pts + i*nts;
  1433.     }
  1434.  
  1435.     recv_packlen = datalen_big + MAXIPLEN + MAXICMPLEN;
  1436.  
  1437.     if (!(recv_packet = (u_char *)malloc((u_int)recv_packlen))) {
  1438.         (void)fprintf(stderr, "bing: out of memory.\n");
  1439.         exit(1);
  1440.     }
  1441.     if (!(options & F_PINGFILLED))
  1442.         for (i = 0; i < datalen_big; ++i)
  1443.             *datap++ = i;
  1444.  
  1445.     hold = 1;
  1446.     if (options & F_SO_DEBUG)
  1447.         icmp_set_option(my_icmp, SOL_SOCKET, SO_DEBUG, (char *)&hold,
  1448.             sizeof(hold));
  1449.     if (options & F_SO_DONTROUTE)
  1450.         (void)icmp_set_option(my_icmp, SOL_SOCKET, SO_DONTROUTE, (char *)&hold,
  1451.             sizeof(hold));
  1452.  
  1453.     /* record route option */
  1454.     if (options & F_RROUTE) {
  1455. #ifdef IP_OPTIONS
  1456.         rspace[IPOPT_OPTVAL] = IPOPT_RR;
  1457.         rspace[IPOPT_OLEN] = sizeof(rspace)-1;
  1458.         rspace[IPOPT_OFFSET] = IPOPT_MINOFF;
  1459.         if (icmp_set_option(my_icmp, IPPROTO_IP, IP_OPTIONS, rspace,
  1460.             sizeof(rspace)) < 0) {
  1461.             perror("bing: record route");
  1462.             exit(1);
  1463.         }
  1464. #else
  1465.         (void)fprintf(stderr,
  1466.           "bing: record route not available in this implementation.\n");
  1467.         exit(1);
  1468. #endif /* IP_OPTIONS */
  1469.     }
  1470.  
  1471.     /*
  1472.      * When pinging the broadcast address, you can get a lot of answers.
  1473.      * Doing something so evil is useful if you are trying to stress the
  1474.      * ethernet, or just want to fill the arp cache to get some stuff for
  1475.      * /etc/ethers.
  1476.      */
  1477.     hold = 48 * 1024;
  1478.     (void)icmp_set_option(my_icmp, SOL_SOCKET, SO_RCVBUF, (char *)&hold,
  1479.         sizeof(hold));
  1480.  
  1481. #ifdef IP_MULTICAST_NOLOOP
  1482.     if (moptions & MULTICAST_NOLOOP) {
  1483.         if (icmp_set_option(my_icmp, IPPROTO_IP, IP_MULTICAST_LOOP,
  1484.                     (char *)&loop, 1) == -1) {
  1485.             perror ("can't disable multicast loopback");
  1486.             exit(92);
  1487.         }
  1488.     }
  1489. #endif
  1490. #ifdef IP_MULTICAST_TTL
  1491.     if (moptions & MULTICAST_TTL) {
  1492.         if (icmp_set_option(my_icmp, IPPROTO_IP, IP_MULTICAST_TTL,
  1493.                     (char *)&ttl, 1) == -1) {
  1494.             perror ("can't set multicast time-to-live");
  1495.             exit(93);
  1496.         }
  1497.     }
  1498. #endif
  1499. #ifdef IP_MULTICAST_IF
  1500.     if (moptions & MULTICAST_IF) {
  1501.         if (icmp_set_option(my_icmp, IPPROTO_IP, IP_MULTICAST_IF,
  1502.                     (char *)&ifaddr, sizeof(ifaddr)) == -1) {
  1503.             perror ("can't set multicast source interface");
  1504.             exit(94);
  1505.         }
  1506.     }
  1507. #endif
  1508.  
  1509.     if (samplefile) {
  1510.         char myname[MAXHOSTNAMELEN];
  1511.         time_t t;
  1512.         gethostname(myname, sizeof myname);
  1513.         t = time(NULL);
  1514.         fprintf(samplefile, "# From %s, %s", myname, ctime(&t));
  1515.         for (i = 0; i < nhosts; i++) {
  1516.         if (phs[i].to->sin_family == AF_INET) {
  1517.             fprintf(samplefile, "# %d\t%s (%s)\n",
  1518.                 i, phs[i].hostname,
  1519.                 inet_ntoa(*(struct in_addr *)&phs[i].to->sin_addr.s_addr));
  1520.         } else {
  1521.             fprintf(samplefile, "# %d\t%s\n",
  1522.                 i, phs[i].hostname);
  1523.         }
  1524.         }
  1525.     }
  1526.  
  1527.     if (nhosts == 2
  1528.         && phs[0].to->sin_family == AF_INET
  1529.         && phs[1].to->sin_family == AF_INET) {
  1530.         (void)printf("BING\t%s (%s) and ",
  1531.             phs->hostname,
  1532.             inet_ntoa(*(struct in_addr *)&phs->to->sin_addr.s_addr));
  1533.         (void)printf("%s (%s)\n\t%d and %d data bytes (%d bits)\n",
  1534.             (phs+1)->hostname,
  1535.             inet_ntoa(*(struct in_addr *)&(phs+1)->to->sin_addr.s_addr),
  1536.             datalen_small, datalen_big, bits);
  1537.     } else if (nhosts == 2) {
  1538.         (void)printf("BING %s and %s:\n\t%d and %d data bytes (%d bits)\n",
  1539.             phs->hostname, (phs+1)->hostname, datalen_small, datalen_big, bits);
  1540.     } else {
  1541.         (void)printf("BING\t%d and %d data bytes (%d bits)\n",
  1542.              datalen_small, datalen_big, bits);
  1543.         for (i = 0; i < nhosts; i++) {
  1544.         if (phs[i].to->sin_family == AF_INET) {
  1545.             (void)printf("%d:\t%s (%s)\n",
  1546.                  i, phs[i].hostname,
  1547.                  inet_ntoa(*(struct in_addr *)&phs[i].to->sin_addr.s_addr));
  1548.         } else {
  1549.             (void)printf("%d:\t%s\n",
  1550.                  i, phs[i].hostname);
  1551.         }
  1552.         }
  1553.     }
  1554.  
  1555. #ifndef WIN32
  1556.     {
  1557.         /* Set the interrupt handler for exit */
  1558.         struct sigaction sa;
  1559.  
  1560.         sa.sa_handler = finishit_exit;
  1561.         sa.sa_flags = 0;
  1562.         sigemptyset(&sa.sa_mask);
  1563.         sigaddset(&sa.sa_mask,SIGINT);
  1564.  
  1565.         sigaction(SIGINT, &sa, NULL);
  1566.     }
  1567. #endif
  1568.  
  1569.     for (nloops = 0; !nloops || nloops < npackets; nloops++) {
  1570.         double oldsecs = -1;
  1571.  
  1572.         if (nloops)
  1573.         fprintf(stderr,"resetting after %ld samples.\n", nsamples);
  1574.  
  1575.         for (i = 0; i < nhosts; i++)
  1576.         for (j = 0; j < nts; j++) {
  1577.             ts_init(&phs[i].ts[j]);
  1578.         }
  1579.  
  1580.         for (ntrans = 0; !nsamples || ntrans < nsamples ; ntrans++) {
  1581.         double secs;
  1582.         double min1b, min1s, min2b, min2s;
  1583.  
  1584.         if (exit_flag) break;
  1585.  
  1586.         for (i = 0; i < nhosts; i++) {
  1587.             struct hoststats *hs1, *hs2;
  1588.             struct timestats *ts1s, *ts1b, *ts2s, *ts2b;
  1589.  
  1590.             if (exit_flag) break;
  1591.  
  1592.             hs2 = phs + i;
  1593.  
  1594.             for (j = datalen_small;
  1595.              j < datalen_big && !exit_flag;
  1596.              j += datalen_step) {
  1597.             ping_and_wait(hs2, j,
  1598.                 (char *)recv_packet, recv_packlen);
  1599.             }
  1600.             if (exit_flag) break;
  1601.             ping_and_wait(hs2, datalen_big,
  1602.             (char *)recv_packet, recv_packlen);
  1603.  
  1604.             if (i == 0)
  1605.                 /* Don't display stats on the first host */
  1606.             continue;
  1607.  
  1608.             hs1 = phs + i-1;
  1609.  
  1610.             ts1b = &hs1->ts[nts-1];
  1611.             ts1s = &hs1->ts[0];
  1612.             ts2b = &hs2->ts[nts-1];
  1613.             ts2s = &hs2->ts[0];
  1614.  
  1615.             if (ts1b->nreceived
  1616.             && ts1s->nreceived == 0
  1617.             && ts2b->nreceived == 0
  1618.             && ts2s->nreceived == 0)
  1619.             continue;
  1620.  
  1621.             min1s = dst_min(&(ts1s->rttstats));
  1622.             min1b = dst_min(&(ts1b->rttstats));
  1623.             min2s = dst_min(&(ts2s->rttstats));
  1624.             min2b = dst_min(&(ts2b->rttstats));
  1625.             adapt_rtt(&min1s, &min1b, &min2s, &min2b);
  1626.             secs = (min2b - min1b) - (min2s - min1s);
  1627.             if ((options & F_NODELTA) || (oldsecs != secs)) {
  1628.             oldsecs = secs;
  1629.             if (options & F_WARN)
  1630.                 warn_rtt(hs1->hostname,
  1631.                      hs2->hostname,
  1632.                      dst_min(&(ts1s->rttstats)),
  1633.                      dst_min(&(ts1b->rttstats)),
  1634.                      dst_min(&(ts2s->rttstats)),
  1635.                      dst_min(&(ts2b->rttstats)));
  1636.             if (secs>0) {
  1637.                 if (bits * 1e3 / secs<1e3)
  1638.                     printf("%s: %6.3fbps  %.3fms %.6fus/bit\n",
  1639.                         hs2->hostname,
  1640.                         bits  * 1e3 / secs,
  1641.                         secs,
  1642.                         secs * 1e3  / bits);
  1643.                 else if ((bits / secs) * 1e3>1e6)
  1644.                     printf("%s: %6.3fMbps %.3fms %.6fus/bit\n",
  1645.                         hs2->hostname,
  1646.                         (bits * 1e3 / secs) / 1e6,
  1647.                         secs,
  1648.                         secs * 1e3  / bits);
  1649.                 else
  1650.                     printf("%s: %6.3fKbps %.3fms %.6fus/bit\n",
  1651.                         hs2->hostname,
  1652.                         (bits * 1e3 / secs) / 1e3,
  1653.                         secs,
  1654.                         secs * 1e3 / bits);
  1655.             } else {
  1656.                 printf("%s: minimum delay difference is zero, can't estimate link throughput\n",
  1657.                     hs2->hostname);
  1658.             }
  1659.             fflush(stdout);
  1660.             }
  1661.         }
  1662.         }
  1663.  
  1664.         finishit();
  1665.         if (exit_flag) break;
  1666.  
  1667.     }
  1668.  
  1669.     if (samplefile) {
  1670.         fclose(samplefile);
  1671.     }
  1672.     icmp_close(my_icmp);
  1673.     return 0;
  1674. }
  1675.